 //============= RECEIVE OSC COMMANDS =========================

// Notes on the message protocol:
// * Top address is either a command for all spots, or the spot indicator ("spot1", "spot2"...)
// * The subaddress define the variable or mode to change (see soundSpot for sound-sending variables).
//   Some of these take VALUES.
// Example of a message: 
//     "/spot2/SendOSCMode/1" means start sending automatically in OSC mode
//     "/spot2/sendingPosition/1" means sending position (in any active mode). 

 // max of two addresses (top and sub), of a max length of 24 characters:
char topAddress[24];
char subAddress[24];

void processOSC() {
  
  // for tests:
   logMessage(&recMes);

  
  if (recMes.getAddressNum()>0) { // otherwise, this means there was a reception error (given the designed protocol)
   strcpy(topAddress,recMes.getAddress(0));
   if (recMes.getAddressNum()>1)  strcpy(subAddress,recMes.getAddress(1)); 
   // NOTE: up to the rest of the program to check if subaddress is really there. 
  
  // First, global commands (for all spots):1
  if ( !strcmp(topAddress, "resetAll" ) ) { 
         spotConfig.allSpotsInit();   
    } 
   // ============================== PRE-DEFINED DEMO MODES ===============================
   else if ( !strcmp(topAddress, "oneContourFollowing" ) ) { 
      spotConfig.oneContourFollowing();
      spotConfig.resetTimer();  
    } 
   else if ( !strcmp(topAddress, "twoContourFollowing" ) ) { 
      spotConfig.twoContourFollowing();
      spotConfig.resetTimer();  
    }
   else if ( !strcmp(topAddress, "oneSimpleBouncing" ) ) { 
      spotConfig.oneSimpleBouncing();
      spotConfig.resetTimer();  
    }
    else if ( !strcmp(topAddress, "twoSimpleBouncing" ) ) { 
      spotConfig.twoSimpleBouncing();
      spotConfig.resetTimer();  
    }
    else if ( !strcmp(topAddress, "oneSnellLaw" ) ) { 
      spotConfig.oneSnellLaw();
      spotConfig.resetTimer();  
    }
     else if ( !strcmp(topAddress, "setAllThresholdMode" ) ) { 
       long mode=recMes.getArgInt(0);
       for(int i=0; i<spotConfig.numSpots; i++) {
         if (mode==0) spotConfig.spotArray[i].setAutoThreshold(false); else spotConfig.spotArray[i].setAutoThreshold(true);
    }
   }
    
    // ============================== GLOBAL SENDING HARDWARE SELECT ===============================
     else if (!strcmp( topAddress, "stopAllSending" ) ) { // note: this stops both global and per-spot sending
      // check consistency of the message? (e.g.: does it really have arguments?):
       if (recMes.getArgInt(0)==0) spotConfig.stopAllSending();
    }
    else if (!strcmp( topAddress, "sendAllOSC" ) ){
      // check consistency of the message? (e.g.: does it really have arguments?):
       if (recMes.getArgInt(0)==0) spotConfig.sendAllOSC=false ; else spotConfig.sendAllOSC=true;
    }
     else if (!strcmp( topAddress, "sendAllSerial" ) ){ 
      // check consistency of the message? (e.g.: does it really have arguments?):
       if (recMes.getArgInt(0)==0) spotConfig.sendAllSerial=false ; else spotConfig.sendAllSerial=true;
    } 
   else if (!strcmp( topAddress, "sendAllMIDI" ) ){ 
      // check consistency of the message? (e.g.: does it really have arguments?):
       if (recMes.getArgInt(0)==0) spotConfig.sendAllMIDI=false ; else spotConfig.sendAllMIDI=true;
    } 
    // ============================== GLOBAL DATA TO BE SENT (through any hardware) =================
    else if( !strcmp( topAddress , "sendAllPosition" ) ) { 
       long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
       if (data==0) spotConfig.sendingAllPosition=false; else spotConfig.sendingAllPosition=true;   
        //pinMode(31, OUTPUT); if (data==0) digitalWrite(31,LOW); else digitalWrite(31, HIGH);                      
     }
    else if( !strcmp( topAddress , "sendAllColor" ) ) { 
       long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
       if (data==0) spotConfig.sendingAllColor=false; else spotConfig.sendingAllColor=true;   
        //pinMode(31, OUTPUT); if (data==0) digitalWrite(31,LOW); else digitalWrite(31, HIGH);                      
     }
    else if( !strcmp( topAddress , "sendAllCollision" ) ) { 
       long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
       if (data==0) spotConfig.sendingAllCollision=false; else spotConfig.sendingAllCollision=true;   
        //pinMode(31, OUTPUT); if (data==0) digitalWrite(31,LOW); else digitalWrite(31, HIGH);                      
     }
    else if( !strcmp( topAddress , "sendAllWall" ) ) { 
       long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
       if (data==0) spotConfig.sendingAllTouchWall=false; else spotConfig.sendingAllTouchWall=true;   
        //pinMode(31, OUTPUT); if (data==0) digitalWrite(31,LOW); else digitalWrite(31, HIGH);                      
     }
     else if( !strcmp( topAddress , "sendAllAngle" ) ) { 
       long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
       if (data==0) spotConfig.sendingAllAngle=false; else spotConfig.sendingAllAngle=true;   
        //pinMode(31, OUTPUT); if (data==0) digitalWrite(31,LOW); else digitalWrite(31, HIGH);                      
     }
    // End of commands for ALL spots
    else {
   // ============================== PER-SPOT ADDRESSING ===============================================
   // Note: toplevel address matching means the spot identifier
   for (int i=0; i<spotConfig.numSpots; i++) {
          if( !strcmp(topAddress,  spotConfig.spotArray[i].spotName) ){ // in this case, we are refering to spot i 
               // Serial.print("Spot Addressed: "); Serial.println(topAddress); 
               //Second level address matching for indicating which parameter to modify. We need to do this with a lot of "ifs":           
                
                // (a)  ------------------- Selection of the sending channel (serial, OSC or Midi), not exclusive  -------------------  
                // Note: check reception error? (e.g., no subaddress)
                if (!strcmp( subAddress, "stopAllSending" ) ) { // note: this per-spot sending (on ANY channel)
                    // check consistency of the message? (e.g.: does it really have arguments?):
                    if (recMes.getArgInt(0)==0) spotConfig.spotArray[i].stopAllSending();
                }
                else if( !strcmp( subAddress , "sendSerial" ) ) { 
                     // Check if it has to start or stop sending data on serial port: 
                     // NOTE: check reception error??
                     if (recMes.getArgInt(0)==0) spotConfig.spotArray[i].sendSerial=false; else spotConfig.spotArray[i].sendSerial=true;
                }
                else if( !strcmp( subAddress , "sendOSC" ) ) { 
                     //Serial.print("Command: "); Serial.print(subAddress); Serial.print(", Argument: "); Serial.println(recMes.getArgInt(0)); 
                     // Check if it has to start or stop sending OSC data over Ethernet: 
                     long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
                     if (data==0) spotConfig.spotArray[i].sendOSC=false; else spotConfig.spotArray[i].sendOSC=true;  
                    // for tests:
                     //pinMode(30, OUTPUT); if (data==0) digitalWrite(30,LOW); else digitalWrite(30, HIGH);                 
                }
                 else if( !strcmp( subAddress , "sendMIDI" ) ) { 
                     // Check if it has to start or stop sending Midi data: 
                    long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
                    if (data==0) spotConfig.spotArray[i].sendMIDI=false; else spotConfig.spotArray[i].sendMIDI=true;                  
                }
                
                // (b) ------------------- Selection of the sending data (through any available channel)  ------------------- 
                else if( !strcmp( subAddress , "sendingPosition" ) ) { 
                    long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
                    if (data==0) spotConfig.spotArray[i].sendingPosition=false; else spotConfig.spotArray[i].sendingPosition=true;   
                     //pinMode(31, OUTPUT); if (data==0) digitalWrite(31,LOW); else digitalWrite(31, HIGH);                      
                }
                else if( !strcmp( subAddress, "sendingAngle" ) ) { 
                       long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
                    if (data==0) spotConfig.spotArray[i].sendingAngle=false; else spotConfig.spotArray[i].sendingAngle=true;
                }
                 else if( !strcmp( subAddress, "sendingColor" ) ) { 
                       long data = recMes.getArgInt(0);  //get received data (should be only one in this case)
                    if (data==0) spotConfig.spotArray[i].sendingColor=false; else spotConfig.spotArray[i].sendingColor=true;
                }
                // .....
                
                // (c) And finally, other parameters not related to sound: 
                else if( !strcmp( subAddress , "kill" ) ) spotConfig.spotArray[i].alive = false;
                else if( !strcmp( subAddress , "resucite" ) ) spotConfig.spotArray[i].alive = true;
                        
                // BEHAVIOUR: 
                // ****** NOTE: better in the future to call a setting function with more default parameters... 
                else if( !strcmp( subAddress , "contourFollowing" ) ) spotConfig.spotArray[i].behaviourMode = COUNTOUR_FOLLOWING; 
                else if( !strcmp( subAddress , "newtonDynamics" ) ) spotConfig.spotArray[i].behaviourMode =  NEWTON_DYNAMICS; 
                else if( !strcmp( subAddress , "simpleBouncing" ) ) spotConfig.spotArray[i].behaviourMode = SIMPLE_BOUNCING; 
                else if( !strcmp( subAddress , "snellLaw" ) ) spotConfig.spotArray[i].behaviourMode = SNELL_LAW; 
                
                // Other controls:
               else if ( !strcmp(subAddress, "setThresholdMode" ) ) { 
                 long mode=recMes.getArgInt(0);
                 if (mode==0) spotConfig.spotArray[i].setAutoThreshold(false); else spotConfig.spotArray[i].setAutoThreshold(true);
                }
                else if( !strcmp( subAddress , "speedUp" ) ) { 
                  // long data = recMes.getArgInt(0);  
                   spotConfig.spotArray[i].vx*=2.0;
                   spotConfig.spotArray[i].vy*=2.0;    
                }
                else if( !strcmp( subAddress , "slowDown" ) ) { 
                   long data = recMes.getArgInt(0);  
                   spotConfig.spotArray[i].vx/=2.0;
                   spotConfig.spotArray[i].vy/=2.0;    
                }
                else if( !strcmp( subAddress , "radius" ) ) { 
                    // Get radius value: 
                    
                }
       
          }
      }
  }
  } else {
    // there was a protocol error, because there is no address in the message (can it happen?)
  }
}

// FOR TESTS ONLY (using the Serial port): 
void logMessage(OSCMessage *mes) {
  
    uint8_t *ip=mes->getIp();
  
    Serial.println(" ");
     //disp ip & port
    Serial.print("from IP:");
    Serial.print(ip[0],DEC);
    Serial.print(".");
    Serial.print(ip[1],DEC);
    Serial.print(".");
    Serial.print(ip[2],DEC);
    Serial.print(".");
    Serial.print(ip[3],DEC);
    Serial.print(" port:");
    Serial.print(mes->getPort(),DEC);
    Serial.print("   ");
    
    //disp adr
    for(int i = 0 ; i < mes->getAddressNum() ; i++){
      
      Serial.print(mes->getAddress(i));
       Serial.print(" ");
      
    }
    
    
    //disp type tags
    Serial.print("  ,");
    for(int i = 0 ; i < mes->getArgNum() ; i++){
      
      Serial.print(mes->getTypeTag(i));
      
    }
    Serial.print(" ");
   
   
   //disp args
    for(int i = 0 ; i < mes->getArgNum() ; i++){
      
      switch( mes->getTypeTag(i) ){
        
        case 'i': {
                      
                      Serial.print( mes->getArgInt(i) );
                  }
          break;
        
        case 'f':  {
                      
                      Serial.print( mes->getArgFloat(i) );
                  }
          break;
         
      }
      
       Serial.print(" ");
      
    }
    
    Serial.println(""); 
    
}

